package com.ruoyi.system.controller;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dyun.tool.mybatis.util.tree.TreeNodeMap;
import com.dyun.tool.mybatis.util.tree.TreeUtils;
import com.dyun.tool.ssecurity.utils.YunSecurityUtils;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.entity.ValidateData;
import com.ruoyi.common.enums.BaseStatusEnum;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.project.setting.security.LoginBody;
import com.ruoyi.project.setting.security.LoginUser;
import com.ruoyi.project.setting.security.service.SysLoginService;
import com.ruoyi.project.setting.security.service.TokenService;
import com.ruoyi.project.setting.security.utils.UserUtils;
import com.ruoyi.project.system.entity.SysMenu;
import com.ruoyi.project.system.entity.SysUser;
import com.ruoyi.project.system.service.ISysMenuService;
import com.ruoyi.project.system.service.ISysUserService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.captcha.service.ICaptchaService;
import net.dreamlu.mica.core.result.R;
import net.dreamlu.mica.core.utils.$;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 登陆 控制层
 *
 * @author dy
 */
@Slf4j
@RestController
@AllArgsConstructor
public class LoginController extends BaseController {

    private final ICaptchaService captchaService;

    private final SysLoginService loginService;

    private final TokenService tokenService;

    private final ISysUserService userService;

    private final ISysMenuService sysMenuService;

    /**
     * 生成验证码
     */
    @GetMapping("/captchaImage")
    public R getCode() {
        String uuid = IdUtil.fastUUID();
        String img = captchaService.generateBase64(uuid);
        ValidateData validateData = new ValidateData();
        validateData.setUuid(uuid);
        validateData.setCode(img);
        return success(validateData);
    }

    /**
     * 用户登陆
     */
    @PostMapping("/login")
    public R login(@Validated @RequestBody LoginBody loginBody) {
        boolean validated = captchaService.validate(loginBody.getUuid(), loginBody.getCode());
        if (!validated) {
            return fail("验证码错误");
        }
        Map<String, Object> map = new HashMap<>(16);

        SysUser user = userService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, loginBody.getUsername()));
        if (user == null || !YunSecurityUtils.getPasswordEncoder().matches(loginBody.getPassword(), user.getPassword())) {
            throw new CustomException("用户不存在/密码错误");
        }
        if (BaseStatusEnum.DB_STATUS_DISABLE.getStatus().equals(user.getStatus())) {
            throw new CustomException("该用户已被停用");
        }

        return success(loginService.login(user));
    }

    /**
     * 用户退出
     */
    @PostMapping("/rylogout")
    public R logout() {
        try {
            LoginUser loginUser = tokenService.currentLoginUser();
            // 删除用户缓存记录
            tokenService.delLoginUser(loginUser.getToken());
            SysLoginService.recordLoginLog(loginUser, BaseStatusEnum.DB_STATUS_SUCCESS.getStatus(), "退出成功");
        } catch (Exception e) {
            log.error(e.getMessage());
            return success();
        }
        return success();
    }

    /**
     * 获取用户信息
     *
     * @return 用户信息
     */
    @GetMapping("/getInfo")
    public R getInfo() {
        // 更新角色权限信息, 不及时更新可返回success(tokenService.getLoginUser().toLoginUserVO)
        LoginUser loginUserOld = tokenService.currentLoginUser();
        SysUser sysUser = userService.getById(loginUserOld.getUserId());
        return success(loginService.initLoginUser(loginUserOld.getToken(), sysUser).toLoginUserVO());
    }

    /**
     * 获取路由信息
     *
     * @return 路由信息
     */
    @GetMapping("/getRouters")
    public R<List<TreeNodeMap>> getRouters() {
        LoginUser loginUser = tokenService.currentLoginUser();
        List<SysMenu> menus;
        // 菜单类型路由
        if (UserUtils.isAdmin(loginUser.getUserId())) {
            menus = sysMenuService.list(new LambdaQueryWrapper<SysMenu>()
                    .eq(SysMenu::getMenuType, UserConstants.TYPE_MENU)
                    .notIn(SysMenu::getStatus, BaseStatusEnum.MENU_STATUS_DISABLE.getStatus())
                    .orderByAsc(SysMenu::getSeq));
        } else {
            menus = loginUser.getResourceList().stream().filter(
                    m -> !BaseStatusEnum.MENU_STATUS_DISABLE.getStatus().equals(m.getStatus()) &&
                            UserConstants.TYPE_MENU.equals(m.getMenuType())).collect(Collectors.toList());
        }
        List<TreeNodeMap> treeNodes = TreeUtils.build(menus, (menu, treeNode) -> {
            treeNode.setId(menu.getId());
            treeNode.setParentId(menu.getParentId());

            Map<String, Object> meta = new HashMap<>(16);
            meta.put("title", menu.getMenuName());
            meta.put("icon", menu.getIcon());

            treeNode.extra("hidden", !BaseStatusEnum.MENU_STATUS_SHOW.getStatus().equals(menu.getStatus()));
            treeNode.extra("name", StringUtils.capitalize(menu.getPath()));
            treeNode.extra("path", $.toStr(getRouterPath(menu), ""));
            treeNode.extra("component", StringUtils.isEmpty(menu.getComponent()) ? UserConstants.LAYOUT : menu.getComponent());

            // 通用iframe特殊处理, 由自己控制路由。
            if (UserConstants.IFRAME_COMPONENT.equals(menu.getComponent())) {
                treeNode.extra("path", "/" + UserConstants.IFRAME_COMPONENT + "/" + menu.getId());
                meta.put("iframe", menu.getPath());
            }
            treeNode.extra("meta", meta);
        });
        return success(treeNodes);
    }

    /**
     * 判断是否增加根路径标识 /
     *
     * @param menu 菜单信息
     * @return 路由地址
     */
    private String getRouterPath(SysMenu menu) {
        String routerPath = menu.getPath();
        // 非外链并且没有上级（类型为菜单）
        boolean addSlash = 0 == menu.getParentId().intValue()
                && UserConstants.NOT_EXTERNAL.equals(menu.getIsExternal())
                && UserConstants.TYPE_MENU.equals(menu.getMenuType());
        if (addSlash) {
            routerPath = "/" + menu.getPath();
        }
        return routerPath;
    }
}
